package com.evendai.sipdemo.sip.audio

import android.annotation.SuppressLint
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.PixelFormat
import android.os.Build
import android.os.IBinder
import android.os.Message
import android.view.*
import com.evendai.loglibrary.Timber
import com.evendai.sipdemo.*
import com.evendai.sipdemo.databinding.OutgoingViewBinding
import com.evendai.sipdemo.sip.listener.FloatViewOnTouchListener
import com.evendai.sipdemo.util.SipUtil
import org.doubango.Whats
import org.doubango.ngn.NgnEngine
import org.doubango.ngn.events.NgnInviteEventArgs
import org.doubango.ngn.events.NgnInviteEventTypes
import org.doubango.ngn.media.NgnMediaType
import org.doubango.ngn.sip.NgnAVSession
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe

/** 电话呼出服务 */
class OutgoingService : Service() {

    private var outgoingSession : NgnAVSession? = null
    private var binding: OutgoingViewBinding? = null
    private var outgoingNumber = ""

    private val broadcaster = object: BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (NgnInviteEventArgs.ACTION_INVITE_EVENT == intent.action && outgoingSession != null) {
                this@OutgoingService.onReceive(intent)
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        registerReceiver(broadcaster, IntentFilter(NgnInviteEventArgs.ACTION_INVITE_EVENT))
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this)
        }
    }


    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(broadcaster)
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this)
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (intent == null) return START_NOT_STICKY
        outgoingNumber = intent.getStringExtra(Keys.OUTGOING_NUMBER) ?: ""
        Timber.i("onStartCommand(), outgoingNumber = $outgoingNumber")

        outgoingSession?.hangUpCall()
        outgoingSession = NgnAVSession.createOutgoingSession(NgnEngine.getInstance().sipService.sipStack, NgnMediaType.Audio)
        outgoingSession?.setSpeakerphoneOn(Constants.sSpeakerphoneOn)
        val makeValidSipUri = SipUtil.makeValidSipUri(outgoingNumber)
        Timber.i("呼出电话：${makeValidSipUri}")
        outgoingSession?.makeCall(makeValidSipUri)
        return START_NOT_STICKY
    }

    fun onReceive(intent: Intent) {
        val args = intent.getParcelableExtra<NgnInviteEventArgs>(NgnInviteEventArgs.EXTRA_EMBEDDED) ?: return
        if(outgoingSession?.id != args.sessionId) return // 如果此消息不是我们的呼出会话，则不用处理

        Timber.i("sessionId = ${args.sessionId}，eventType = ${args.eventType}，mediaType = ${args.mediaType}")
        // 拨出时会依次收到如下eventType事件：
        // INPROGRESS   此状态表示正在呼出
        // LOCAL_TRANSFER_TRYING
        // MEDIA_UPDATING
        // LOCAL_TRANSFER_TRYING

        // 对方接听时会收到如下eventType事件：
        // LOCAL_TRANSFER_TRYING
        // CONNECTED

        // 对方挂机时会收到如下eventType事件：
        // TERMINATED

        if (!NgnMediaType.isAudioVideoType(args.mediaType)) {
            Timber.fe(Exception("不是音视频类型，不处理, mediaType = ${args.mediaType}"))
            // 其它类型有：NgnMediaType.isFileTransfer(mediaType)、NgnMediaType.isChat(mediaType)
            return
        }

        when (args.eventType) {
            NgnInviteEventTypes.INPROGRESS -> showOutgoingView()
            NgnInviteEventTypes.TERMINATED -> {
                closeOutgoingView()
                stopSelf()
                outgoingSession = null
            }
            NgnInviteEventTypes.CONNECTED -> {
                binding?.tvCallState?.text = outgoingNumber
                val isAudioMeeting = SipUtil.isAudioMeeting(outgoingNumber)
                if (isAudioMeeting) { // 会议电话需要发sip消息请求听说权限
                    SipUtil.requestSpeakPermission(outgoingNumber)
                }
            }
            else -> { }
        }
    }

    private fun hangupCall() {
        Timber.i("挂电话")
        outgoingSession?.hangUpCall()
        outgoingSession = null
    }

    /** 显示呼出电话悬浮窗 */
    @Suppress("DEPRECATION")
    @SuppressLint("ClickableViewAccessibility", "SetTextI18n")
    fun showOutgoingView() {
        closeOutgoingView()

        val binding = OutgoingViewBinding.inflate(LayoutInflater.from(App.getContext()), null, false).also { binding = it }
        binding.btnHangupCall.setOnClickListener { hangupCall(); closeOutgoingView() }
        binding.tvCallState.text = "正在呼叫..."

        val floatViewType = when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 -> WindowManager.LayoutParams.TYPE_PHONE
            else -> WindowManager.LayoutParams.TYPE_TOAST
        }

        val windowManager = App.getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val params = WindowManager.LayoutParams().apply {
            type = floatViewType
            flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE // 不设置这个flag的话，屏幕上任何内容都没法接收触摸事件了
            width = WindowManager.LayoutParams.WRAP_CONTENT
            height = WindowManager.LayoutParams.WRAP_CONTENT
            gravity = (Gravity.END or Gravity.BOTTOM)
            format = PixelFormat.TRANSLUCENT
        }
        binding.root.setOnTouchListener(FloatViewOnTouchListener(params, windowManager))
        windowManager.addView(binding.root, params)
    }

    private fun closeOutgoingView() {
        val outgoingView = binding?.root
        if (outgoingView != null) {
            (App.getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager).removeView(outgoingView)
            binding = null
        }
    }

    override fun onBind(intent: Intent): IBinder? = null

    @Suppress("unused")
    @Subscribe
    fun setSpeakerphoneOn(message: Message) {
        if (message.what == Whats.SET_SPEAKERPHONE_ON) {
            val speakerOn = message.obj as Boolean
            outgoingSession?.setSpeakerphoneOn(speakerOn)
            Timber.i("收到扬声器开关消息，speakerOn = $speakerOn")
        }
    }
}